<?php

namespace App\Service\Kms\SelfCheck;

use App\Error\Kms\HomeError;
use App\Exceptions\KfHttpResponseException;
use App\Http\Resources\Activity\B\ShopOrderActivityDataStatisticsResource;
use App\Http\Resources\Kms\SelfCheck\ReportListsResource;
use App\Models\Clickhouse\Guanyuan\GyDailyDeliveryReportCHModel;
use App\Models\Cruise\CruiseCheckSelfDetailModel;
use App\Models\Cruise\CruiseTemplateModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\Shop\ShopModel;
use App\Service\BaseService;
use App\Service\Kms\Home\HomeService;
use App\Service\Kms\Task\UserRoleService;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use Tinderbox\Clickhouse\Exceptions\ClientException;

class SelfCheckService extends BaseService
{
    /**
     * 门店自检数据统计看板
     *
     * @param object $params
     * @return array[]
     */
    public static function groupStatusStatistical(object $params): array
    {
        $showStatusMap = [
            CruiseCheckSelfDetailModel::STATUS_1,
            CruiseCheckSelfDetailModel::STATUS_3,
            CruiseCheckSelfDetailModel::STATUS_4,
            CruiseCheckSelfDetailModel::STATUS_9,
        ];

        $baseQuery = CruiseCheckSelfDetailModel::buildHomeSearchQuery(
            $params->role,
            attributeGet($params, "regionSelectionType", -1),
            attributeGet($params, "region", ""),
            attributeGet($params, "regionValue", "")
        )->where(
            "templateType", CruiseTemplateModel::TYPE_8
        )->where(
            "cruiseOrderId", ">", 0
        )->when(
            checkFieldLen($params, "startDate"),
            function ($query) use ($params) {
                $query->where(CruiseCheckSelfDetailModel::timeQuery(
                    $params->startDate,
                    $params->endDate,
                    checkFieldLen($params, "checkType") ? explode(",", $params->checkType) : []
                ));
            },
            function ($query) use ($params) {
                $query->when(checkFieldLen($params, "checkType"), function ($query) use ($params) {
                    $query->whereIn("sysTemplate", explode(",", $params->checkType));
                });
            }
        )->when(checkFieldLen($params, "activeDaysShop"),
            function ($query) use ($params) {
                if (((int)$params->activeDaysShop) > 0) {
                    $shopCodes = GyDailyDeliveryReportCHModel::getActivityShopLists($params->activeDaysShop);
                    if ($shopCodes) {
                        $query->whereIn(
                            "shopId",
                            ShopModel::query()->whereIn("shopCode", $shopCodes)
                                     ->pluck("id")->toArray()
                        );
                    } else {
                        $query->where("shopId", 0);
                    }
                }
            });

        $groupQueryRes = (clone $baseQuery)->groupBy("status")->select([
            "status",
            DB::raw('count(distinct shopId) as total')
        ])->get();


        return [
            "groupCount" => collect(CruiseCheckSelfDetailModel::NEW_STATUS_TEXT)
                ->only($showStatusMap)->map(function ($text, $status) use ($groupQueryRes) {
                    return [
                        "status" => $status,
                        "text"   => $text,
                        "total"  => attributeGet($groupQueryRes->where("status", $status)->first(), "total", 0)
                    ];
                })->values()->merge([
                    [
                        "status" => 0,
                        "text"   => "全部",
                        "total"  => (clone $baseQuery)->pluck("shopId")->unique()->count()
                    ]
                ])->toArray()
        ];
    }

    /**
     * 门店自检数据统计看板 - 门店列表
     *
     * @param object $params
     * @return array[]
     */
    public static function groupStatusStatisticalShop(object $params): array
    {
        $baseQuery = CruiseCheckSelfDetailModel::buildHomeSearchQuery(
            $params->role,
            attributeGet($params, "regionSelectionType", -1),
            attributeGet($params, "region", ""),
            attributeGet($params, "regionValue", "")
        )->where(
            "templateType", CruiseTemplateModel::TYPE_8
        )->where(
            "cruiseOrderId", ">", 0
        )->when(
            checkFieldLen($params, "startDate"),
            function ($query) use ($params) {
                $query->where(CruiseCheckSelfDetailModel::timeQuery(
                    $params->startDate,
                    $params->endDate,
                    checkFieldLen($params, "checkType") ? explode(",", $params->checkType) : []
                ));
            },
            function ($query) use ($params) {
                $query->when(checkFieldLen($params, "checkType"), function ($query) use ($params) {
                    $query->whereIn("sysTemplate", explode(",", $params->checkType));
                });
            }
        )->when(checkFieldLen($params, "activeDaysShop"), function ($query) use ($params) {
            if (((int)$params->activeDaysShop) > 0) {
                $shopCodes = GyDailyDeliveryReportCHModel::getActivityShopLists($params->activeDaysShop);
                if ($shopCodes) {
                    $query->whereIn(
                        "shopId",
                        ShopModel::query()->whereIn("shopCode", $shopCodes)->pluck("id")->toArray()
                    );
                } else {
                    $query->where("shopId", 0);
                }
            }
        });

        $statusShopIdsCollection = (clone $baseQuery)->when(
            $params->status,
            function ($query) use ($params) {
                $query->where("status", $params->status);
            }
        )->pluck("shopId")->unique();

        $count = $statusShopIdsCollection->count();

        $paginate    = (clone $baseQuery)->whereIn("shopId", $statusShopIdsCollection->toArray())->with([
            "shopRel" => function ($query) {
                return $query->select("name", "id", "shortName", "shopCode");
            }
        ])->groupBy(["shopId"])->select([
            DB::raw(" SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS status_1_count"),
            DB::raw(" SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS status_2_count"),
            DB::raw(" SUM(CASE WHEN status = 4 THEN 1 ELSE 0 END) AS status_4_count"),// 待审核
            DB::raw(" SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) AS status_3_count"),
            DB::raw(" SUM(CASE WHEN status = 9 THEN 1 ELSE 0 END) AS status_9_count"),
            DB::raw(" SUM(CASE WHEN status = 10 THEN 1 ELSE 0 END) AS status_10_count"),
            DB::raw("
                CASE WHEN (
                SUM(CASE WHEN status = 4 THEN 1 ELSE 0 END) +
                SUM(CASE WHEN status = 9 THEN 1 ELSE 0 END) +
                SUM(CASE WHEN status = 10 THEN 1 ELSE 0 END)
                ) = 0 THEN 0
            ELSE ROUND(
            (SUM(CASE WHEN status = 9 THEN 1 ELSE 0 END) + SUM(CASE WHEN status = 10 THEN 1 ELSE 0 END)) /
            (
            SUM(CASE WHEN status = 9 THEN 1 ELSE 0 END) +
            SUM(CASE WHEN status = 10 THEN 1 ELSE 0 END) +
            SUM(CASE WHEN status = 4 THEN 1 ELSE 0 END)
            ),2)
                END AS reviewedRate
            "),
            "shopId",
        ])->when(
            checkFieldLen($params, "sortField"),
            function ($query) use ($params) {
                $query->orderBy($params->sortField, $params->sortOrder == "descend" ? "desc" : "asc");
            },
            function ($query) {
                $query->orderBy("status_1_count", "desc");
            }
        )->orderBy("shopId")->paginate(
            $params->pageSize,
            ['*'],
            'pageNum',
            $params->pageNum
        );
        $groupResult = collect($paginate->items());


        return [
            "count"    => $count,
            "pageSize" => $params->pageSize,
            "pageNum"  => $params->pageNum,
            "list"     => $groupResult->map(function ($row) {
                $row->shopRel->name = str_replace(["夸父炸串", "(", ")", "（", "）"], "", $row->shopRel->name);
                return $row;
            })->values()->toArray()
        ];
    }

    /**
     * 自检报告列表
     *
     * @param object $params
     * @return array
     * @throws ValidationException
     */
    public static function selfCheckReportLists(object $params): array
    {
        if (checkFieldLen($params, "shopId")) {// 指定门店查询报告
            $query = CruiseCheckSelfDetailModel::query()->where(function ($query) use ($params) {
                if ($params->role == UserRoleService::ROLE_BASE_SUPERVISOR) {
                    $shopIds = [];
                    // 督导权限
                    $signOrder = OpenShopSignOrderModel::query()->whereHas("checkAcceptRel", function ($query) {
                        $query->where("managerId", auth()->user()->rmsUserId);
                    })->get();
                    if ($signOrder->isNotEmpty()) {
                        $shopIds = ShopModel::query()
                                            ->whereIn("shopCode", $signOrder->pluck("shopCode")->toArray())
                                            ->pluck("id")
                                            ->toArray();
                    }

                    if ($shopIds) {
                        $query->whereIn("shopId", $shopIds);
                    } else {
                        $query->where("id", 0);
                    }
                } else {
                    $userRole = UserRoleService::getUserRole(auth()->user()->rmsUserId);
                    if (!$userRole["userResponsibleArea"]["all"]) {
                        $shopModel = ShopModel::query()->where(function ($query) use ($userRole) {
                            $query->whereIn("province", $userRole["userResponsibleArea"]["area"]["province"])
                                  ->orWhereIn("city", $userRole["userResponsibleArea"]["area"]["city"])
                                  ->orWhereIn("district", $userRole["userResponsibleArea"]["area"]["district"]);
                        })->where("id", $params->shopId)->first();
                        if (!$shopModel) {
                            $query->where("shopId", 0);
                        }
                    }
                }
                $query->where("shopId", $params->shopId);
            });
        } else {
            $query = CruiseCheckSelfDetailModel::buildHomeSearchQuery(
                $params->role,
                attributeGet($params, "regionSelectionType", -1),
                attributeGet($params, "region", ""),
                attributeGet($params, "regionValue", "")
            );
        }

        $query = $query->where(
            "templateType", CruiseTemplateModel::TYPE_8
        )->where(
            "cruiseOrderId", ">", 0
        );

        $baseQuery = (clone $query)->when(
            checkFieldLen($params, "startDate"),
            function ($query) use ($params) {
                $query->where(CruiseCheckSelfDetailModel::timeQuery(
                    $params->startDate,
                    $params->endDate,
                    checkFieldLen($params, "checkType") ? explode(",", $params->checkType) : []
                ));
            },
            function ($query) use ($params) {
                $query->when(checkFieldLen($params, "checkType"), function ($query) use ($params) {
                    $query->whereIn("sysTemplate", explode(",", $params->checkType));
                });
            }
        )->when(checkFieldLen($params, "status"), function ($query) use ($params) {
            $query->whereIn("status", explode(",", $params->status));
        });

        $paginate = (clone $baseQuery)->with([
            "shopRel" => function ($query) {
                return $query->select("name", "id", "shopCode", "shortName");
            }
        ])->orderByDesc("submitTime")->orderBy("id")->skip($params->count)->take($params->pageSize)->get();

        if (checkFieldLen($params, "shopId")) {
            $approvalQuery = $query;
        } else {
            $approvalQuery = $baseQuery;
        }

        return array_merge([
            "reportList" => ReportListsResource::collection($paginate),
            "count"      => $params->count,
            "pageSize"   => $params->pageSize,
            "count"      => (clone $baseQuery)->count()
        ], ($params->count == 0 ? [
            "todayApproval" => (clone $approvalQuery)->whereIn("status", [
                CruiseCheckSelfDetailModel::STATUS_10,
                CruiseCheckSelfDetailModel::STATUS_9
            ])->whereBetween("finishTime", [
                Carbon::now()->startOfDay()->timestamp,
                Carbon::now()->endOfDay()->timestamp
            ])->count(),
            "weekApproval"  => (clone $approvalQuery)->whereIn("status", [
                CruiseCheckSelfDetailModel::STATUS_10,
                CruiseCheckSelfDetailModel::STATUS_9
            ])->whereBetween("finishTime", [
                Carbon::now()->startOfWeek()->timestamp,
                Carbon::now()->endOfWeek()->timestamp
            ])->count()
        ] : []));
    }

    /**
     * 门店列表
     *
     * @param object $params
     * @return array
     * @throws ValidationException
     */
    public static function shopLists(object $params): array
    {
        $userRole = UserRoleService::getUserRole(auth()->user()->rmsUserId);
        if ($userRole["role"] == UserRoleService::ROLE_SPECIAL_NO_ACCESS) {
            throw new KfHttpResponseException(HomeError::CURRENT_ROLE_HAS_NO_PERMISSION_ACCESS_CURRENT_MODULE);
        }

        $lists = ShopModel::query()->where(function ($query) use ($userRole) {
            if ($userRole["role"] == UserRoleService::ROLE_BASE_SUPERVISOR) {
                $shopIds = [];
                // 督导权限
                $signOrder = OpenShopSignOrderModel::query()->whereHas("checkAcceptRel", function ($query) {
                    $query->where("managerId", auth()->user()->rmsUserId);
                })->get();
                if ($signOrder->isNotEmpty()) {
                    $shopIds = ShopModel::query()
                                        ->whereIn("shopCode", $signOrder->pluck("shopCode")->toArray())
                                        ->pluck("id")
                                        ->toArray();
                }

                if ($shopIds) {
                    $query->whereIn("id", $shopIds);
                } else {
                    $query->where("id", 0);
                }
            } else {
                if (!$userRole["userResponsibleArea"]["all"]) {
                    $query->whereIn("province", $userRole["userResponsibleArea"]["area"]["province"])
                          ->orWhereIn("city", $userRole["userResponsibleArea"]["area"]["city"])
                          ->orWhereIn("district", $userRole["userResponsibleArea"]["area"]["district"]);
                }
            }
        })->where(function ($query) use ($params) {
            $query->where("name", "like", "%{$params->keywords}%")
                  ->when(((int)$params->keywords) > 0, function ($query) use ($params) {
                      $query->orWhere("shopCode", "like", "%{$params->keywords}%");
                  });
        })->limit(200)->select(["id", "shopCode", "name", "address", "shortName"])->get();

        return [
            "shopLists" => $lists->map(function (ShopModel $shopModel) {
                $shopModel->name = str_replace(["夸父炸串", "(", ")", "（", "）"], "", $shopModel->name);
                return $shopModel;
            })->values()->toArray()
        ];
    }

    /**
     * @param object $params
     * @return array
     */
    public static function selfCheckDetail(object $params): array
    {
        $cruiseCheckSelfDetailModel = CruiseCheckSelfDetailModel::query()
                                                                ->with("shopRel")
                                                                ->where("cruiseOrderId", $params->cruiseOrderId)
                                                                ->where("templateType", CruiseTemplateModel::TYPE_8)
                                                                ->first();


        return [
            "reportDetail" => ReportListsResource::collection([$cruiseCheckSelfDetailModel])->getIterator()->current()
        ];
    }
}
